package com.zhongpengcheng.controller.common;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.core.lang.Snowflake;
import com.zhongpengcheng.adapter.RedisAdapter;
import com.zhongpengcheng.blog.enums.ResultCodeEnum;
import com.zhongpengcheng.blog.event.TimedCacheDataEvent;
import com.zhongpengcheng.blog.exception.CaptchaException;
import com.zhongpengcheng.blog.pojo.ro.CaptchaRO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.zhongpengcheng.blog.enums.ResultCodeEnum.CAPTCHA_HAS_EXPIRED;

/**
 * 公共服务接口，提供如下服务<br>
 * <ul>
 *     <li>心跳</li>
 *     <li>服务器环境配置读取</li>
 *     <li>验证码获取</li>
 *     <li>验证码验证</li>
 * </ul>
 *
 * @author zhongpengcheng
 */
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {

    @Autowired
    private ConfigurableApplicationContext context;
    /**
     * 可过时缓存
     */
    @Autowired
    private RedisAdapter strRedis;
    /**
     * 个位数四则运算验证码生成器
     */
    @Autowired
    private MathGenerator mathGenerator;
    /**
     * 验证码ID生成器
     */
    @Autowired
    private Snowflake captchaIdGenerator;
    @Value("${captcha.width:160}")
    private Integer captchaWidth;
    @Value("${captcha.height:160}")
    private Integer captchaHeight;
    @Value("${captcha.expire:60}")
    Integer captchaExpire;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 打招呼
     *
     * @param name 打招呼对象的名称
     * @return 招呼信息
     */
    @GetMapping("/{name}/hello")
    public String sayHello(@PathVariable String name) {
        return String.format("Hey %s, now is %d", name, System.currentTimeMillis());
    }

    /**
     * 获取环境配置项
     *
     * @return -
     */
    @GetMapping("/env")
    public Map<String, Object> getEnvironment() {
        return context.getEnvironment().getSystemEnvironment();
    }

    /**
     * 获取Java配置项
     *
     * @return -
     */
    @GetMapping("/prop")
    public Map<String, Object> getProperties() {
        return context.getEnvironment().getSystemProperties();
    }

    /**
     * 获取验证码
     */
    @GetMapping("/captcha")
    public CaptchaRO getCaptcha() {
        // 配置验证码参数
        LineCaptcha lineCaptcha = generateCaptcha();
        String captchaId = captchaIdGenerator.nextIdStr();
        // 获取base64格式的验证码
        String imageBase64 = lineCaptcha.getImageBase64Data();
        String code = lineCaptcha.getCode();
        log.info("生成验证码：[{}]-[{}]", captchaId, code);
        if (strRedis.hasKey(captchaId)) {
            // 验证码ID重复，抛出异常
            throw new CaptchaException(ResultCodeEnum.CAPTCHA_ID_DUPLICATE);
        }
        // 缓存置入事件
        eventPublisher
                .publishEvent(new TimedCacheDataEvent(captchaId, code, captchaExpire, TimeUnit.SECONDS));

        return CaptchaRO.builder().imageBase64(imageBase64).captchaId(captchaId).build();
    }

    /**
     * 验证验证码
     *
     * @param inputCode 用户输入的验证码
     * @param captchaId 验证码ID
     * @return 验证成功返回true，否则返回false
     * @throws CaptchaException 验证码不存在或已过期时抛出该异常
     */
    @GetMapping("/captcha/valid/{captchaId}/{inputCode}")
    public Boolean validCaptcha(@PathVariable String inputCode, @PathVariable String captchaId)
            throws CaptchaException {
        String code = strRedis.get(captchaId);
        if (code == null) {
            throw new CaptchaException(CAPTCHA_HAS_EXPIRED);
        }
        return mathGenerator.verify(code, inputCode);
    }

    /**
     * 生成验证码
     *
     * @return 线性验证码对象
     */
    private LineCaptcha generateCaptcha() {
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaWidth, captchaHeight);
        lineCaptcha.setGenerator(mathGenerator);
        return lineCaptcha;
    }
}
